package com.hontech.pastacooking.task.conn

import com.hontech.pastacooking.app.bus
import com.hontech.pastacooking.conn.*
import com.hontech.pastacooking.event.OtaProgEvent
import com.hontech.pastacooking.serial.ByteView
import com.hontech.pastacooking.serial.UInt16
import com.hontech.pastacooking.serial.UInt32
import java.security.MessageDigest

class OtaCtx(val addr: Int, val start: Int, val translate: Int, val complete: Int)

val mainOtaCtx =
    OtaCtx(Addr.Main, MainProto.OtaStart, MainProto.OtaTranslate, MainProto.OtaComplete)
val heatOtaCtx =
    OtaCtx(Addr.Heator, HeaterProto.OtaStart, HeaterProto.OtaTranslate, HeaterProto.OtaComplete)
val weightOtaCtx =
    OtaCtx(Addr.Weight, WeightProto.OtaStart, WeightProto.OtaTranslate, WeightProto.OtaComplete)

class DeviceOtaTask(val ctx: OtaCtx, val data: ByteArray) {

    private val pkgSize = data.size
    private var pkgIndex = 0
    private var pkgId = 0

    companion object {
        const val Timeout = 5 * 1000L
        const val MaxPkg = 32
    }

    suspend fun run() {
        start()
        translate()
        complete()
    }

    private suspend fun start() {
        Device.request(
            Timeout,
            ctx.addr,
            ctx.start,
            arrayOf(UInt32(pkgSize)),
            "ota start 异常"
        )
    }

    private suspend fun translate() {
        while (pkgIndex < pkgSize) {
            var n = pkgSize - pkgIndex
            if (n > MaxPkg) {
                n = MaxPkg
            }
            Device.request(
                Timeout,
                ctx.addr,
                ctx.translate,
                arrayOf(UInt16(pkgId), ByteView(data, pkgIndex, n)),
                "ota translate 异常"
            )
            pkgIndex += n
            pkgId++
            bus.post(OtaProgEvent(ctx.addr, pkgIndex * 100 / pkgSize))
        }
    }

    private suspend fun complete() {
        val m5 = MessageDigest.getInstance("MD5").digest(data)
        Device.request(
            Timeout,
            ctx.addr,
            ctx.complete,
            arrayOf(ByteView(m5)),
            "ota complete 异常"
        )
    }

}


suspend fun runOta(ctx: OtaCtx, data: ByteArray) {
    DeviceOtaTask(ctx, data).run()
}

